#include "AIPlayer.h"
//#include <iostream>
#include <sstream>
#include "Card.h"
//#include <QTCore>

using namespace std;

AIPlayer::AIPlayer(Hand h, int i, game* g,Client* c):Player(h,i,g,c)
{
    localHand.updateHandInfo();
    partnerIndex=0;
    highestBid.num=0;
    highestBid.suit="P";
    opener=true;
    //leadSuit = '_';
}
// this function alerts the AI to the last move made
void AIPlayer::sendBid(QStringList b,int player)
{

    opener=false;

    qDebug()<<"AIPlayer send bid = "<<b;

    Bid temp;
    ostringstream t_suit;
    ostringstream t_num;
    string bid;

    if(b.at(0).compare("P")==0)
    {
        bid=b.at(0).toUtf8().constData();
        bid.append(b.at(1).toUtf8().constData());
    }
    else
    {
        bid=b.at(2).toUtf8().constData();
        bid.append(b.at(1).toUtf8().constData());
    }

    //cout<<"Bid = "<<bid;
    for(int i=0; i<bid.length(); i++)
    {
        if(!isdigit(bid[i]))
            t_suit<<bid[i];
        else
            t_num<<bid[i];
    }

    temp.suit=b.at(3);
    stringstream(t_num.str()) >>temp.num;

    if(partnerIndex==player)
        partnerLastBid=temp;
    setHighestBid(temp);
    playerBids[player].push_back(temp);


    // For updating the latest bid on the gui
    qDebug()<<"send bid";
    QString str;
    str.append(b.at(0));
    str.append(" ");
    str.append(b.at(1));
    str.append(" ");
    str.append(b.at(2));
    str.append(b.at(3));
    gui->sendBid(str);

}

void AIPlayer::sendMove(QStringList list,int player)
{

    qDebug()<<"at start "<<leadSuit;
    qDebug()<<"Got move "<<list;

    // build a string with the move information
    string temp = list.at(1).toUtf8().constData();
    char suit= temp[0];
    string value = list.at(2).toUtf8().constData();

    Card card(suit, 0, player, value);

//    card.print();
    // update the move on the gui
    gui->displaymove(card, player);
    gui->changeSouthHand(&localHand);


        playedCards.addCard(card);
        if(currTrick->getHandSize()==0)
            leadSuit=card.suit;
        currTrick->addCard(card);

//if the card is in player's local hand remove the card
       localHand.removeCard(card);

//if the card is in dummy hand remove the card
       if(partner!=NULL)
       {
        partner->localHand.removeCard(card);
        gui->show_Dummy(&partner->localHand);
       }


       qDebug()<<"in the end "<<leadSuit;


}

// function returs a hand containing all the valid moves that the AI can make
Hand AIPlayer::getValidMoves(char ls)
{
    Hand hand;
    qDebug()<<"get valid moves in AIPlayer";

    qDebug()<<"Trick suit in valid moves "<<ls;

    if(ls=='_'  /*trumpSuit.compare("NT")==0*/ || localHand.numberOfSuit(ls)<=0)
    {
        return localHand;
    }
    else
    {

            Card *t_card;
            for(int i=0;i<localHand.getHandSize();i++)
            {
                t_card=localHand.getCard(i);

                if(t_card->suit==ls /*|| t_card->suit==trumpSuit[0]*/)
                {
                    hand.addCard(*t_card);
                }
            }
    }

    return hand;
}


void AIPlayer::getMove(bool playForDummy)
{
    qDebug()<<"GetMove Function "<<playForDummy;

   // QThread::msleep(500);
    Hand h;
    Card *highestCard;
    QString dummyName="";

    if(playForDummy)
    {

        // if AI has to play for dummy

        qDebug()<<id<<"Play for dummy " <<partner->id;
        qDebug()<<"Leadsuit in getMove"<<leadSuit;
        h = partner->getValidMoves(leadSuit); // get all valid moves
        qDebug()<<"Valid moves";
        h.print();
        qDebug()<<"=====================================";
        qDebug()<<"Partner";
        partner->print();
        dummyName=QString::fromStdString(partner->getUsername());
    }
    else
    {
        // AI playes from his own hand
        h = getValidMoves(leadSuit); // get all valid moves
        qDebug()<<"Valid moves";
        h.print();
        qDebug()<<"=====================================";
        qDebug()<<"Play self";
        print();
    }

    if(currTrick->getHandSize()<=0)
    {
        // open the trick with the biggest card
        client->sendMove (*openTrick(h));  // ask client to send move to game master
    }
    else
    {
        qDebug()<<"Not first to play";
        highestCard=currTrick->getMaxCard(); // get the biggest card in current trick
//        highestCard->print();
//        qDebug()<<"can beat = "<<canBeat(h,highestCard);
        if(!canBeat(h,highestCard))
        {
            qDebug()<<"Can't beat"; // can't beat current trick, pick smallest card to discard
           client->sendMove( *(h.getMinCard()));// ask client to send move to game master

        }
        else
        {
            qDebug()<<"Can beat"; // can beat current trick, get the lowest card that can beat the current trick
           client->sendMove(*(getLowestBeatCard(h,highestCard)) );// ask client to send move to game master

        }

    }
}

void AIPlayer::getBid()
{
    Bid tempBid;
    QStringList bid;
    tempBid.action="B";
    tempBid.suit="S";
    tempBid.num=2;

    localHand.updateHandInfo();

        //action,count,suit
        if(numInvalidBids>=3)
        {
            numInvalidBids=0;
            tempBid.action="P";
            //cout<<"|"<<tempBid.num<<tempBid.num<<tempBid.suit<<"|\n";

           // bid.append(QString::fromStdString(tempBid.action));
           // cout<<"here";
            bid.append("P");
            bid.append((tempBid.suit));
            bid.append(QString::number(tempBid.num));
            //return bid;

        }


        if(opener)
        {
            qDebug()<<"Opening bid";
            tempBid=getOpeningBid(); // open bidding


        }
        else
        {
            qDebug()<<"respond bid";
            tempBid=getRespondBid();// respond to a bid

        }
       // qDebug() << QString::fromStdString(tempBid.action);
       // bid.append(QString::fromStdString(tempBid.action));


       //cout<<"|"<<tempBid.action<<tempBid.num<<tempBid.suit<<"|\n";
        bid.append((tempBid.action));
        bid.append(QString::number(tempBid.num));               // build a QStringList with bid information
        bid.append((tempBid.suit));

        //return bid;
        client->sendBid(bid); // ask client to end out bid to game master

}

//Hand getValidMoves();

void AIPlayer::sendHand()
{
    gui->changeSouthHand(&localHand);       // update GUI with local hand
}


bool AIPlayer::setLocalHand(Hand h)
{
    localHand=h;
    qDebug()<<"AI has local hand";
}

Bid AIPlayer::getRespondBid()
{
     //cout<<"respond\n";
   // cout<<"Highest bid = "<< highestBid.suit<<highestBid.num<<"\n";
      Bid ret;
     ret.action="P";
     ret.num=0;
        qDebug()<<"======================= Respond ==========================";
     qDebug()<<"Hand score "<<localHand.getHandScore()<<"Highest bid "<<highestBid.num;

     switch(highestBid.num)
     {
         case 2:{ if(localHand.getHandScore()<10) ret.action="P"; ret.suit="0";return ret;}
         case 3:{ if(localHand.getHandScore()<15)  ret.action="P"; ret.suit="0";return ret;}
         case 4:{ if(localHand.getHandScore()<20)  ret.action="P"; ret.suit="0";return ret;}    // compare hand with highest bid
         case 5:{ if(localHand.getHandScore()<27)  ret.action="P"; ret.suit="0";return ret;}
         case 6:{ if(localHand.getHandScore()<33)  ret.action="P"; ret.suit="0";return ret;}
         case 7:{ if(localHand.getHandScore()<37)  ret.action="P"; ret.suit="0";return ret;}

     }

     ret.action="B";
     if(localHand.getHandScore()>4)
     {
        if(localHand.getHandScore()>=10)  // raise the current bid
        {
            qDebug()<<"Raise";
           // cout<<"|3|\n";
            ostringstream oss;
            char t_suit=localHand.getLongestSuit();
            oss<<t_suit;
            ret.suit=QString::fromStdString(oss.str());
            ret.num=1;
            //cout<< ret.suit<<ret.num<<"\n";

            qDebug()<< ret.suit<<ret.num;


            while(compareBids(ret,highestBid)<=0)
            {
                qDebug()<<"increase bid";
                ret.num++;
               // cout<<"while"<<ret.num;
                if( ret.num>7)
                {
                    ret.action="P";
                    ret.num=0;
                    break;
                }
            }
             qDebug()<< ret.suit<<ret.num;
            //cout<< ret.suit<<ret.num<<"\n";
        }
         else       // hand not strong enough, so pass
         {
             ret.action="P";
             ret.num=0;
             return ret;
         }
       // return ret;

     }
     else
     {
        // hand not strong enough, so pass
       ret.action="P";
       ret.num=0;
     }

     return ret;
}

Bid AIPlayer::getOpeningBid() // return a opening bid based on the 4321 point count
{

    Bid open;
    open.action="B";

    char suit=localHand.getLongestSuit();

    qDebug()<<"Longest suit = "<<suit;

    if(localHand.getHandScore()<13)
    {

        switch(localHand.numberOfSuit(suit))
        {
            case 6:{open.suit=suit;
                    open.num=2;
                     return open;}
        case 7:{open.suit=suit;
                open.num=3;
                 return open;}
        case 8:{open.suit=suit;
                open.num=3;
                 return open;}
        };
    }
    else if(localHand.getHandScore()<15)
    {
        open.suit=suit;
        open.num=1;
        return open;
    }
    else if(localHand.getHandScore()<17)
    {
        open.suit="NT";
        open.num=1;
        return open;
    }
    else if(localHand.getHandScore()<20)
    {
        open.suit=suit;
        open.num=1;
        return open;
    }
    else if(localHand.getHandScore()<21)
    {
        open.suit="NT";
        open.num=2;
        return open;
    }
    else if(localHand.getHandScore()<25)
    {
        open.suit="C";
        open.num=2;
        return open;
    }
    else if(localHand.getHandScore()==25)
    {
        switch (suit)
        {
            case'S':
                {
                    open.suit="S";
                    open.num=4;
                    return open;
                }
            case'H':
                {
                    open.suit="H";
                    open.num=4;
                    return open;
                }
            default:
            {
                open.suit="NT";
                open.num=3;
                return open;
            }
        };


    }
    else if(localHand.getHandScore()<28)
    {
        open.suit="NT";
        open.num=3;
        return open;
    }
    else if(localHand.getHandScore()==29)
    {
        switch (suit)
        {
            case'D':
                {
                    open.suit="D";
                    open.num=5;
                    return open;
                }
            case'C':
                {
                    open.suit="C";
                    open.num=5;
                    return open;
                }
            default:
            {
                open.suit="NT";
                open.num=3;
                return open;
            }
        };
    }
    else if(localHand.getHandScore()<33)
    {
        open.num=6;
        switch (suit)
        {
            case'S':{open.suit="S";break;}
            case'H':{open.suit="H";break;}
            case'C':{open.suit="C";break;}
            case'D':{open.suit="D";break;}
        };
        return open;
    }
    else if(localHand.getHandScore()<37)
    {
        open.num=7;
        switch (suit)
        {
            case'S':{open.suit="S";break;}
            case'H':{open.suit="H";break;}
            case'C':{open.suit="C";break;}
            case'D':{open.suit="D";break;}
        };
        return open;
    }

    open.suit=localHand.getLongestSuit();
    open.num=1;
    return open;
}
void AIPlayer::setHighestBid(Bid a)  // update the current highest bid
{
    string suits[6]={"P","D","C","H","S","NT"};
    bool hasHigh=false;
    qDebug()<<"Set highest bid";
    qDebug()<<a.suit<<a.num;
    if(compareBids(a,highestBid)>0)
    {
        highestBid.suit=a.suit;
        highestBid.num=a.num;
    }
    qDebug()<<highestBid.suit<<highestBid.num;
}
int AIPlayer::compareBids(Bid a,Bid b) // compare two bids if a<b return -1; if a>b return 1; if a==b return 0
{
    QString suits[6]={"P","C","D","H","S","NT"};

        bool hasA=false;

        if(a.num<b.num)
            return -1;
        else if(a.num>b.num)
            return 1;
        else
        {
            if(a.suit.compare(b.suit)==0)
            return 0;
            else
            {
                for(int i=0;i<6;i++)
                {
                    if(a.suit.compare(suits[i])==0)     // assigns a int value to the suits of the bids
                        hasA=true;

                    if(b.suit.compare(suits[i])==0 && hasA)
                        return -1;

                    else if(b.suit.compare(suits[i])==0 && !hasA)
                        return 1;
                }
            }
        }
        return 1;
}

void AIPlayer::startDealing()
{
    gui->newGame();// alert gui that a new game has started
}

void AIPlayer::startRedealing()
{

}

void AIPlayer::startBidding()
{
    opener=true;        //reset variables for new game
    numInvalidBids=0;
}

void AIPlayer::startPlay()
{
    //ªdelete currTrick;
    currTrick=new Hand();// reset variable for new trick
    leadSuit='_';
}

void AIPlayer::sendTrickWinner(QString winner)
{
    qDebug()<<"send trick winner from AIPlayer";
    delete currTrick;
    currTrick=new Hand();
    leadSuit='_';
    gui->endTrick();            // send trick information to gui
    gui->trickWinner(winner);
}


void  AIPlayer::sendGameStatus(QStringList a)
{

}

void AIPlayer::sendContract(QStringList con)
{
    qDebug()<<"AI contract" << con;
    trumpSuit=con.at(1);
    QString string;                         // save contract information and trump suit
    string.append(con.at(0));
    string.append(con.at(1));
    gui->sendContract(string);              // send contract to gui
    qDebug() << "Finished contract setting";
}

void AIPlayer::setTrumpSuit(char a)
{
    trumpSuit=a;                    // set trump suit
}

void AIPlayer::sendDummyId(int dummy)
{
    qDebug()<<"Dummy id start in AI";
    switch (id) {
    case 0:dummy+=2;                // update dummy position for gui
        break;
    case 1:dummy+=1;
        break;
    case 2:break;
    case 3:dummy-=1;
        break;
    }
    qDebug()<<"Before GUI";
        gui->setDummy(dummy);       // tell gui the dummy location
        qDebug()<<"Dummy id end in AI";
}

void AIPlayer::sendDummyCards(Hand dHand)
{
    qDebug()<<"=================   Create a new dummy";
    partner=new AIPlayer(dHand,0,gui,client);
    partner->print();
    gui->show_Dummy(&dHand);            // ask gui to show dummy cards
}

void AIPlayer::sendScoreUpdate(QString wa,QString wb,QString ta,QString tb)
{
    gui->set_score(wa, wb, ta, tb);                         //update score on gui
}

void AIPlayer::sendGameWinner(QString winner)
{
    gui->gameWinner(winner);        //update game winner on gui
}

bool AIPlayer::canBeat(Hand hand,Card *card)
{
    qDebug()<<"Start can beat";
   // if(card==NULL)
      //  return true;

    for(int i=0;i<hand.getHandSize();i++)   // test if AI can beat a card
        if(*(card)<*(hand.getCard(i)))
            return true;
    return false;

}

Card* AIPlayer::openTrick(Hand hand)
{
    //qDebug()<<"open trick";
    //localHand.print();
    //qDebug()<<"===================================";


    return hand.getMaxCard();       // get biggest card to open trick
}

Card* AIPlayer::getLowestBeatCard(Hand hand,Card *high)
{

    Card *card;
    for(int i=0;i<hand.getHandSize();i++)  // get lkowest card from hand that can beat the current trick
    {
        card=hand.getCard(i);
        if(*card>*high)
            return card;
    }
     return card;
}
